/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.cloudbus.cloudsim.power.models.scheduling.client;

import java.util.ArrayList;
import org.cloudbus.cloudsim.Log;
import org.cloudbus.cloudsim.core.CloudSimTags;
import org.cloudbus.cloudsim.core.SimEntity;
import org.cloudbus.cloudsim.core.SimEvent;
import org.cloudbus.cloudsim.power.models.scheduling.Middleware;
import sun.misc.Compare;
import sun.misc.Sort;

/**
 *
 * @author Márcio Costa Junior - University of Sao Paulo, Montana State University
 */
public class ClientManager extends SimEntity implements Compare{
    
    private ArrayList<Middleware> mids;
    
    private Report [] report;
    
    private int updateId;
    
    private boolean lessCost;
    
    public ClientManager(ArrayList<Middleware> mids, int size){
        super("Client_Manager");
        
        setMids(mids); 
        report = new Report[size];
        lessCost = true;
    }   
    
    private void createReport(){
        
        for(int i = 0; i < getMids().size(); i++){
            report[i] = new Report();
            report[i].setMidId(i);
            report[i].setCost(getMids().get(i).getCosts());
            report[i].setReceive(true);
            report[i].setMaxCanReceive(1000);///chaaaaaaaange here later
        }
        
    }
    
    private void organizeReports(){
         
        Sort.quicksort(report, this);
    }
    
    private void updateCost(Object obj){
        
        report[updateId].setCost((Long) obj);
    }
    
    private void updateStatus(Object obj){
        
        report[updateId].setReceive((Boolean) obj);
    }
    
    private void updateMIPS(Object obj){
        
        report[updateId].setMaxCanReceive((Integer) obj);
    }
    

    @Override
    public void startEntity() {
        Log.printLine("The Client Manager is starting");
        createReport();
    }

    @Override
    public void processEvent(SimEvent ev) {
        switch (ev.getTag()){
			
                case CloudSimTags.CLIENT_ASK:
                        receiveRequest(ev.getData());	
                break;
                case CloudSimTags.MANAGER_UPDATE:
                        updateId = (Integer) ev.getData();	
                break;
                case CloudSimTags.MANAGER_UPDATE_COST:
                        updateCost(ev.getData());	
                break;
                case CloudSimTags.MANAGER_UPDATE_STATUS:
                        updateStatus(ev.getData());	
                break;
                case CloudSimTags.MANAGER_UPDATE_MIPS:
                        updateMIPS(ev.getData());	
                break;
                default:
                       Log.printLine("Message not found");
		}
    }

    @Override
    public void shutdownEntity() {
        Log.printLine("The Client Manager is shutting down");
    }
    
    private void receiveRequest(Object obj){
        Request rq = (Request) obj;
        
        ArrayList<Middleware> anwMids = new ArrayList<Middleware>();
        
        if(rq.getPreference() == Request.LESS_NETWORK_DELAY)
            for(Job job : rq.getJobs()){
                anwMids.add(searchForMidLND(job));
            }
        else
        if(rq.getPreference() == Request.LESS_ENERGY_COSTS)
            for(Job job : rq.getJobs()){
                anwMids.add(searchForMidLEC(job));
            }
        
        AnswerPackage pkg = new AnswerPackage(rq.getJobs(), anwMids, rq.getPreference());
        send(rq.getClientId(), 0, CloudSimTags.CLIENT_ANSWER, pkg);       
    }
    
    private Middleware searchForMidLND(Job job){
        
        lessCost = false;
        
        organizeReports();
        
        for(int i = 0; i < report.length; i++){
            if(report[i].getMaxCanReceive() >= job.getVm().getMips() && report[i].isReceive())
                return mids.get(i);
        }
        return null;
    }
    
    private Middleware searchForMidLEC(Job job){
        
        lessCost = true;
        
        organizeReports();
        
        for(int i = 0; i < report.length; i++){
            if(report[i].getMaxCanReceive() >= job.getVm().getMips() && report[i].isReceive())
                return mids.get(i);
        }
        
        return null;
    }
    

    /**
     * @return the mids
     */
    public ArrayList<Middleware> getMids() {
        return mids;
    }

    /**
     * @param mids the mids to set
     */
    public void setMids(ArrayList<Middleware> mids) {
        this.mids = mids;
    }

    public int doCompare(Object o, Object o1) {
        
        Report r1 = (Report) o;
        Report r2 = (Report) o1;
        
        if(r1.getCost() < r2.getCost())
            return 1;
        else
        if(r1.getCost() > r2.getCost())
            return -1;
        else
            return 0;
        
    }
    
    
    
}
